package com.mp.approvalreq.service.impl;

import com.mp.approvalreq.dao.*;
import com.mp.approvalreq.dao.impl.*;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.service.ApprovalCommentServiceServant;
import com.mp.approvalreq.util.DbName;
import com.mp.approvalreq.util.ErrorUtils;
import com.mp.approvalreq.util.RocketUtils;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.jdbc.util.DBUtils;
import com.plusmoney.util.DateTimeHelper;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

public class ApprovalCommentServantImpl implements ApprovalCommentServiceServant {

    private static final Logger logger = LoggerFactory.getLogger(ApprovalCommentServantImpl.class);

    @Override
    public List<Comment> getRequestCommentList(Integer requestId, Integer companyInfoId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            CommentDao commentDao = new CommentDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);
            List<Comment> comments = commentDao.selectCommentList(requestId);
            if (Utils.isNotEmpty(comments)) {
                List<Integer> commentIds = comments.stream().map(Comment::getId).collect(Collectors.toList());
                Map<Integer, String> readTimeMap = redDao.selectCommentReadTimeMap(companyInfoId, Utils.list2string(commentIds));

                for (Comment comment : comments) {
                    if (!readTimeMap.containsKey(comment.getId()) || Objects.equals(comment.getCreateCompanyInfoId(), companyInfoId)) {
                        // 自己评论的或历史红点数据被删,默认设置为创建时间
                        comment.setReadTime(comment.getCrtTime());
                    } else {
                        comment.setReadTime(readTimeMap.get(comment.getId()));
                    }
                }
            }
            return comments;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public Comment addApprovalComment(Comment comment, User user) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            RequestDao requestDao = new RequestDaoImpl(connection);
            CommentDao commentDao = new CommentDaoImpl(connection);
            RedDao redDao = new RedDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            ParticipantDao participantDao = new ParticipantDaoImpl(connection);

            user = userServicePrx.getUserByContactId(user.getContactId());
            Request request = getRequest(comment.getRequestId(), requestDao, ccDao, flowDao, participantDao);
            if (request.getFinished() == Finished.CALLING_BACK) {
                throw new RpcServerLogicalException(1, "审批状态已变更，请返回列表");
            }

            DBUtils.begin(connection);
            //  添加评论
            comment.setCreateId(user.getContactId());
            comment.setCompanyId(user.getCompanyId());
            comment.setCreateCompanyInfoId(user.getCompanyInfoId());
            int commentId = commentDao.insertComment(comment);
            comment.setId(commentId);

            insertRedPointAndPushMsg(comment, user, request, redDao);
            DBUtils.commit(connection);
            return comment;
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private Request getRequest(Integer requestId, RequestDao requestDao, CcDao ccDao, FlowDao flowDao, ParticipantDao participantDao) throws SQLException {
        Request request = requestDao.selectRequestDetailById(requestId);
        request.setCcList(ccDao.selectCcListByRequestId(request.getRequestDkey()));
        request.setFlows(flowDao.selectFlowsByRequestId(request.getRequestDkey()));
        request.setParticipants(participantDao.selectParticipantsByRequestId(request.getRequestDkey()));
        return request;
    }

    private void insertRedPointAndPushMsg(Comment comment, User user, Request request,
                                          RedDao redDao) throws Throwable {
        int commentType = getCommentType(comment);
        logger.info("commentType:{}", commentType);

        List<Integer> contactIds = getRedPointContactIds(request, commentType);

        UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);
        List<User> users = userService.getUserListByContactIds(Utils.list2string(contactIds));

        users.removeIf(o -> o.getCompanyInfoId().equals(user.getCompanyInfoId()));

        if (Utils.isEmpty(users)) {
            return;
        }
        List<Integer> atRedPointUserIds = new ArrayList<>();
        if (StringUtils.isNotBlank(comment.getNotifyUser())) {
            atRedPointUserIds = Utils.string2list(comment.getNotifyUser());
        }
        List<MessageRead> messageReads = new ArrayList<>();
        for (User u : users) {
            MessageRead messageRead = new MessageRead();
            messageRead.setMessageId(comment.getId());
            messageRead.setCompanyInfoId(u.getCompanyInfoId());
            messageRead.setCompanyId(user.getCompanyId());
            messageRead.setContactId(u.getContactId());
            messageRead.setCreatorId(user.getContactId());
            messageRead.setRequestId(request.getRequestDkey());
            if (commentType == 1 && Objects.equals(u.getContactId(), request.getApplicant())) {
                messageRead.setIsRefuse(1);
            }
            if (atRedPointUserIds.contains(u.getUserId())) {
                messageRead.setIsAtRed(1);
            }
            messageReads.add(messageRead);
        }
        logger.info("插入红点信息:{}", messageReads.stream().map(MessageRead::getCompanyInfoId).collect(Collectors.toList()));
        redDao.insertBatchRedPoints(messageReads);

        insertAtPushMsg(request, comment, users, user);

        RocketUtils.pushToRefresh(user, contactIds);
    }

    private void insertAtPushMsg(Request request, Comment comment, List<User> users, User user) {
        try {
            List<Integer> userIds = users.stream().map(User::getUserId).collect(Collectors.toList());
            if (Utils.isEmpty(userIds)) {
                return;
            }
            List<Integer> notifyUserIds = StringUtils.isEmpty(comment.getNotifyUser()) ? new ArrayList<>() : Utils.string2list(comment.getNotifyUser());

            List<Integer> atUserIds = ListUtils.intersection(userIds, notifyUserIds);
            RocketUtils.pushToAtUsers(atUserIds, request, getPushMsgTitle(comment, user.getContactName()), user.getContactName());

            List<Integer> notAtUserIds = ListUtils.removeAll(userIds, atUserIds);
            RocketUtils.pushToOthers(notAtUserIds, request, getPushMsgTitle(comment, user.getContactName()));
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
    }

    private String getPushMsgTitle(Comment comment, String commentUser) {
        String msg;
        if (comment.getType() == 1 || comment.getType() == 2) {
            msg = commentUser + "上传附件";

        } else {

            msg = comment.getMsg();
        }

        return msg;
    }

    private List<Integer> getRedPointContactIds(Request request, int commentType) {
        List<Integer> contactIds = new ArrayList<>();
        // 申请人
        contactIds.add(request.getApplicant());
        // 代申请人
        if (Utils.isNotNull(request.getProxyContactId()) && request.getProxyContactId() > 0) {
            logger.info("=====代申请人=====:{}", request.getProxyContactId());
            contactIds.add(request.getProxyContactId());
        }

        // 如果是驳回原因,只推送给申请人
        if (commentType == 1) {
            return contactIds;
        }
        List<Integer> flowContactIds = request.getFlows().stream().filter(flow -> flow.getIsApproved() >= 0).map(Flow::getContactId).collect(Collectors.toList());
        logger.info("=====审批人=====:{}", flowContactIds);
        if (request.getFinished() == 0) {
            // 待批准
            contactIds.addAll(flowContactIds);
        } else if (request.getFinished() == 1 || request.getFinished() == 2) {
            // 已批准/归档
            contactIds.addAll(flowContactIds);
            if (Utils.isNotEmpty(request.getCcList())) {
                List<Integer> ccContactIds = request.getCcList().stream().map(Cc::getCcId).collect(Collectors.toList());
                contactIds.addAll(ccContactIds);
            }
        } else if (request.getFinished() == -2) {
            // 已作废
            contactIds.addAll(flowContactIds);
        } else if (request.getFinished() == 3) {
            // 驳回
            contactIds.addAll(flowContactIds);
        }
        // 参与人
        if (Utils.isNotEmpty(request.getParticipants())) {
            List<Integer> participantIds = request.getParticipants().stream().map(Participant::getContactId).collect(Collectors.toList());
            logger.info("=====参与人=====:{}", participantIds);
            contactIds.addAll(participantIds);
        }

        return contactIds;
    }

    /**
     * 返回评论类型:  0 - 普通评论(上传文件、图片、文字评论); 1 - 驳回评论; 2 - 艾特评论
     *
     * @param comment
     * @return
     */
    private int getCommentType(Comment comment) {
        // 审批人没有填写驳回原因时, 前端会手动填写"驳回了该审批"内容,但是isRefuse = 0
        if (Objects.equals("驳回了该审批", comment.getMsg())) {
            return 1;
        }

        if (comment.getIsRefuse() == 1) {
            return 1;
        }

        if (StringUtils.isNotEmpty(comment.getNotifyUser())) {
            return 2;
        }

        return 0;
    }


    @Override
    public int cancelComment(Comment dto, User user) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            int flag = 0;
            CommentDao commentDao = new CommentDaoImpl(connection);
            Comment comment = commentDao.selectCommentById(dto.getId());

            // 评论不存在或者已被撤销
            if (comment == null || comment.getIsCancel() == 1) {
                return flag;
            }
            // 评论不存在或者已被撤销
            Comment lastComment = commentDao.selectLastComment(comment.getRequestId());
            if (lastComment == null) {
                return flag;
            } else {
                // 已有新评论无法撤回
                if (lastComment.getId() != dto.getId()) {
                    flag = 2;
                } else {
                    long crtTime = DateTimeHelper.parse(comment.getCrtTime(), DateTimeHelper.YEAR_MONTH_DAY_HOUR_MINUTE_PATTERN).getTime();
                    long timeLimit = System.currentTimeMillis() - crtTime;
                    // 超过时间限制
                    if (timeLimit > 2 * 60 * 1000) {
                        flag = 3;

                    } else {
                        DBUtils.begin(connection);
                        commentDao.UpdateCommentCancelStatus(comment.getId());
                        DBUtils.commit(connection);
                        flag = 1;
                    }
                }
            }
            return flag;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            DBUtils.rollback(connection);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Integer> getCanAtUserList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            CcDao ccDao = new CcDaoImpl(connection);
            FlowDao flowDao = new FlowDaoImpl(connection);
            ParticipantDao participantDao = new ParticipantDaoImpl(connection);

            Request request = getRequest(query.getRequestId(), requestDao, ccDao, flowDao, participantDao);

            return collectCanAtUser(request);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private List<Integer> collectCanAtUser(Request request) {

        int finished = request.getFinished();
        if (finished == Finished.DELETED || finished == Finished.CALLING_BACK) {
            throw new RpcServerLogicalException(1, "当前审批状态无法评论");
        }

        Set<Integer> ids = request.getFlows().stream().filter(flow -> flow.getIsApproved() >= 0).map(Flow::getContactId).collect(Collectors.toSet());
        logger.info("操作过的审批人:{}", ids);
        if (finished == Finished.AGREED || finished == Finished.ARCHIVED || finished == Finished.CANCELLED) {
            if (Utils.isNotEmpty(request.getCcList())) {
                List<Integer> ccIds = request.getCcList().stream().map(Cc::getCcId).collect(Collectors.toList());
                logger.info("抄送人:{}", ccIds);
                ids.addAll(ccIds);
            }
        }

        // 参与人
        if (Utils.isNotEmpty(request.getParticipants())) {
            List<Integer> participantIds = request.getParticipants().stream().map(Participant::getContactId).collect(Collectors.toList());
            logger.info("参与人:{}", participantIds);
            ids.addAll(participantIds);
        }

        // 申请人
        ids.add(request.getApplicant());
        logger.info("该审批可以艾特人群:" + ids);

        return new ArrayList<>(ids);
    }
}
